home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
301-325
/
disk_313
/
uucp
/
uucp1.lzh
/
src
/
uucico
/
uucico.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-01-25
|
33KB
|
1,462 lines
/*
* UUCICO.C
*
* (C) Copyright 1987 by John Gilmore.
* Copying and use of this program are controlled by the terms of the Free
* Software Foundation's GNU Emacs General Public License.
*
* Derived from:
* i[$]uuslave.c 1.7 08/12/85 14:04:20
* which came from the ACGNJ BBS system at +1 201 753 9758. Original
* author unknown.
*
* Ported to Amiga by William Loftus
* Amiga Changes Copyright 1988 by William Loftus. All rights reserved.
* Additional Major Changes (c)Copyright 1989 by Matthew Dillon, All rights reserved
*
* 14-Oct-89, moved modem_init() to before poll_sys.
*
* -r option (-r1 does a call out to all systems we have mail for)
* -D[EVICE] dev sets serial device name (automatic from Getty)
* -U[NIT] unit sets unit name (automatic from Getty)
* -h0 Ignore CD (carrier detect)
*/
#include "/version.h"
#include "includes.h" /* System include files, system dependent */
#include "uucp.h" /* Uucp definitions and parameters */
#include "sysdep.h" /* System dependent parts of gnuucp */
#include "modem.h" /* Modem commands */
#include <log.h>
#include <tmpfile.h>
int sigint();
void modem_init();
void cleanup();
#define MAX_FLAGS 40
extern int errno;
IDENT(".06");
static char *Copyright = COPYRIGHT;
char ttynam[NAMESIZE], /* Name of tty we use as serial port */
srcnam[NAMESIZE], /* Source file name */
dstnam[NAMESIZE], /* Dest file name */
who[NAMESIZE] = "-", /* Who sent the file */
flags[MAX_FLAGS], /* Flags from file xfer cmd */
temp[NAMESIZE]; /* Temp file name */
int ourpid = 0, /* Our process ID */
ignore_time_restrictions = 0, /* Call out even if L.sys sez no */
mode; /* File mode from file xfer cmd */
char host_name[MAX_HOST] = "AmigaUUCP"; /* Other guy's host name */
char our_name[MAX_HOST]; /* Our uucp hostname, set from usenet.ctl */
char path[128];
int debug = -1; /* -1 indicates not set by command line or ctl file */
int f_wait = 0; /* wait for a call (-w) or calls (-w -e) after outbnd */
int loop = 0; /* Loop accepting logins if tty name specified */
int curtemp = 0;
int Overide = 0; /* overide modem protocol */
int Getty = 0; /* -Getty initiated */
int IgnoreCD= 0; /* xgetc() should ignore carrier? */
int OurNameOv= 0;
int WindowOne= 0;
#define MAX_STRING 200 /* Max length string to send/expect */
#define MSGO2IDX 7
/* We print these prompts */
char msgo0[] = "login: ";
char msgo1[] = "Password:";
char msgo2[10+MAX_HOST] = { "\20Shere" }; /* NO = */
char msgo3[] = "\20ROK\0";
char msgo3a[]= "\20P";
char msgo3b[]= "\20Pg\0";
char msgo4[] = "\20OOOOOOO\0";
/* We expect to receive these strings */
char msgi0[] = "uucp\r";
char msgi1[] = "s8000\r";
/* char msgi2[] = "\20S*\0"; We now scan it specially FIXME */
char msgi3[] = "\20Ug\0";
char msgi4[] = "OOOOOO";
#define SPOOLDIR "UUSPOOL:"
/*
* Protocol switch data structure
*/
extern int gturnon(), grdmsg(), gwrmsg(), grddata(), gwrdata(), gturnoff();
#define turnon gturnon
#define rdmsg grdmsg
#define wrmsg gwrmsg
#define rddata grddata
#define wrdata gwrdata
#define turnoff gturnoff
int
getname(isshere)
{
int data, count = 0;
static char msgi[MAX_STRING+SLOP]; /* Incoming trash buffer */
/* Read data until null character */
while ((data = xgetc(BYTE_TO)) != EOF) {
data &= 0x7F;
if (data == 020)
break;
}
if (data == EOF)
return FAIL;
while ((data = xgetc(BYTE_TO)) != EOF && (data & 0x7F)) {
data &= 0x7F;
if (count == 0 && data != 'S')
continue;
if (count > sizeof(msgi) - 2)
continue;
msgi[count++] = (char)data;
}
msgi[count] = 0;
if (debug > 8)
printf("GETNAME MSG (%d): %s\n", count, msgi);
if (msgi[0] != 'S')
return FAIL;
if (isshere) {
for (count = 1; msgi[count] && msgi[count] != '='; ++count);
if (msgi[count] == '=')
++count;
} else {
count = 1;
}
if (msgi[count]) {
if (debug > 8)
printf("Compare host names: '%s' '%s'\n", host_name, msgi + count);
strcpy (host_name, msgi + count);
}
strtok(host_name, " "); /* put \0 after hostname */
if (debug > 8)
printf("Hostname is '%s'\n", host_name);
return SUCCESS;
}
/*
* get_proto() checks the list of protos given by the foriegn machine
* checking for 'g' (which is the only proto we have). Use only in master
* mode.
*/
int
get_proto()
{
int data;
while ((data = xgetc(BYTE_TO)) != EOF) {
data &= 0x7F;
if (data == 0)
break;
if (data == 'g')
return(SUCCESS);
}
return FAIL;
}
/*
* Medium level input routine.
*
* Look for an input string for the send-expect sequence.
* Return 0 for matching string, 1 for timeout before we found it.
* FIXME: we only time out if the other end stops sending. If it
* keeps sending, we keep listening forever.
*/
instr(s, n)
char *s;
int n;
{
int data,count,j;
int i;
static char msgi[512]; /* Incoming trash buffer */
count = 0;
if (debug > 8) {
printf("Expecting ");
for (i = 0; i < n; i++)
printc(s[i]);
printf("\n");
}
while ((data = xgetc(BYTE_TO)) != EOF) {
msgi[count++] = (char)data & 0x7F;
if (count == sizeof(msgi)) { /* throw away first half */
count = sizeof(msgi) / 2;
bcopy(msgi + sizeof(msgi) / 2, msgi, sizeof(msgi) / 2);
}
if (count >= n) {
for (i = n - 1, j = count - 1; i >= 0; i--, j--) {
if (*(s+i) != msgi[j])
break;
}
if (i < 0) {
if (debug > 8)
printf("\n");
return(0);
}
}
}
if (debug > 8)
printf("\n");
msgi[count] = (char)0;
return(1);
}
/*
* Debugging hack for stuff written to the modem.
*/
int
twrite(s, n)
char *s;
int n;
{
int i;
if (debug > 8) {
printf("Wrote: ");
for (i = 0; i < n; i++)
printc(s[i]);
printf("\n");
}
return xwrite(s, n);
}
/*
* MAIN ROUTINE.
*
* This is called at program startup. It parses the arguments to the
* program (if any) and sets up to receive a call on the modem.
*
* If there are no arguments, we assume the caller is already on standard
* input, waiting to do uucp protocols (past the login prompt), and we
* just handle one caller.
*
* If there is an argument, it is the name of the tty device where we
* should listen for multiple callers and handle login and password.
*/
void
main(argc,argv)
int argc;
char *argv[];
{
int i;
char *poll_sys = (char *)NULL; /* System name to poll, or none */
short rmode = 0; /* 1 = master, 0 = slave */
LogProgram = "uucico";
LogHost = host_name;
LogWho = who;
signal(SIGINT,sigint); /* Allow the user to break */
/* FIXME, use getopt */
/* scan command line arguments, kinda kludgy but it works */
for (i = 1; i < argc; ++i) {
if (argv[i][0] != '-') {
printf("uucico: warning, extra args ignored: %s\n", argv[i]);
break;
}
switch (argv[i][1]) {
case 'N':
strcpy(our_name, argv[i] + 2);
OurNameOv = 1;
break;
case 'D': /* Serial Device */
{
extern char *DeviceName;
DeviceName = argv[++i];
}
break;
case 'U': /* Serial Unit */
{
extern long DeviceUnit;
DeviceUnit = atoi(argv[++i]);
}
break;
case 'g':
case 'G':
Getty = 1;
break;
case 'h':
IgnoreCD = atoi(argv[i] + 2);
break;
case 'w':
++f_wait;
break;
case 'r':
rmode = atoi(&argv[i][2]);
break;
case 'x':
debug = atoi(&argv[i][2]);
LogLevel = debug;
LogToStdout = 1;
printf("uucico: debug level set to %d\n", debug);
break;
case 'o':
Overide = 1;
break;
case 'n':
WindowOne = 1; /* force windowing mode to size=1 */
break;
case 'S':
ignore_time_restrictions++;
case 's':
poll_sys = &argv[i][2];
break;
case 'e':
++loop;
break;
/* Is -t needed for MSDOS? Why? -- hoptoad!gnu */
case 't':
curtemp++;
printf("uucico: using ~uutemp.$$$ for temp file\n");
break;
default:
printf("uucico: warning, bad flag %s\n", argv[i]);
break;
}
}
/* If argument provided, use it as name of comm port */
/* FIXME, this needs some thought. */
getcwd(path,128);
if (chdir(SPOOLDIR)) {
perror("Can't chdir to Spool directory");
exit(2);
}
read_ctl(); /* Read control file FIXME */
/*
* If running via getty/login, our debug stdout had better
* go to a file, not to the usual stdout!
*/
if (debug > 0 && Getty) {
freopen("T:uuslave.log", "a", stdout);
}
setvbuf(stdout, NULL, _IOLBF, 0);
/* Timestamp the long debug log */
if (debug > 0) {
long clock;
time(&clock);
printf("\014\nuuslave log on tty '%s' starting %s\n",
ttynam, ctime(&clock));
}
/* Log our presence so we humans reading the logs can find the
entries created by uuslave. */
ulog(-1, "Startup %s", VERSION);
amiga_setup();
modem_init();
if (poll_sys) {
if (*poll_sys == '\0')
poll_sys = (char *)NULL;
call_system(poll_sys);
if (!f_wait)
goto end;
} else {
if (rmode) {
do_outbound();
if (!f_wait)
goto end;
}
}
do {
/*
* Set up serial channel, wait for incoming call.
*/
DEBUG(0, "\nRestarting\n", 0);
if (Getty == 0 && Overide == 0)
openline();
do_session(Getty);
hangup();
DEBUG(0, "\nEnd of call\n", 0);
} while (loop && !Getty);
end:
cleanup();
}
/*
* translate embedded escape characters
*/
void
xlat_str(msg, out)
char *msg;
char *out;
{
int i = 0;
int cr = 1;
/*int j = 0;*/
while (msg[i]) {
if (msg[i] == '\\') {
switch (msg[++i]) {
case 'r': /* carriage return */
twrite("\r", 1);
/*out[j++] = 0x0d;*/
break;
case 'n': /* line feed */
twrite("\n", 1);
/*out[j++] = 0x0a;*/
break;
case '\\': /* back slash */
twrite("\\", 1);
/*out[j++] = '\\';*/
break;
case 't': /* tab */
twrite("\t", 1);
/*out[j++] = '\t';*/
break;
case 'b':
SendBreak();
break;
case 'd': /* delay */
Delay(180);
break;
case 's': /* space */
twrite(" ", 1);
/*out[j++] = ' ';*/
break;
case 'c': /* no CR at end */
cr = 0;
break;
default: /* don't know so skip it */
break;
}
++i;
} else {
twrite(msg + i, 1);
++i;
/*out[j++] = msg[i++];*/
}
}
if (cr) {
twrite("\r", 1);
/*out[j++] = 0x0d;*/
}
/*out[j] = '\0';*/
}
/*
* Read the control file and grab a few parameters.
*/
read_ctl()
{
FILE *fd;
static char buf[MAX_CTLLINE];
if (!(fd = fopen("UULIB:Config", "r"))) {
printf("Can't Find config file");
chdir(path);
exit(3);
}
/* find path to inbound news */
while (NULL != fgets(buf, sizeof buf, fd)) {
if (strncmp(buf, "NodeName", 8) == 0) {
if (OurNameOv == 0)
strcpy(our_name, strtok(&buf[9], CTL_DELIM) ) ;
} else if (strncmp(buf, "Debug", 5) == 0)
if (debug < 0)
debug = atoi(strtok(&buf[6], CTL_DELIM));
}
fclose(fd);
return (1);
}
/*
* Search spool queues for work, call the systems we need to call.
*/
do_outbound()
{
return call_system((char *)NULL);
}
/*
* Call a specific system, or all systems that have work pending.
*/
call_system(sys)
char *sys;
{
FILE *lsys;
static char buf[MAX_LSYS];
static char sysnam[MAX_HOST];
static char prev_name[MAX_HOST];
int called = FAIL;
/*
* Unix uucico just reads the directory, and calls the systems
* in the order of the files in the directory. We want more
* control than that, though I'm not sure that L.sys order is
* best either. For example, in the first call after 11PM,
* I'd like to call the sites that haven't been callable before
* 11PM first, and finish up with the ones I've been able to call
* all day. FIXME.
*/
if (! (lsys = fopen("UULIB:L.sys", "r"))) {
DEBUG(0, "uucico: can't open L.sys, errno %d\n", errno);
return 0;
}
sysnam[0] = '\0'; /* Initially, no previous sys */
/* Once per system in L.sys... */
/* FIXME, handle continuation lines (trailing "\") */
while (fgets(buf, sizeof buf, lsys)) {
if (buf[0] == '#' || buf[0] == '\n')
continue;
/*
* Grab the system name. If same as previous, and
* the previous call worked, skip it.
*/
strcpy(prev_name, sysnam);
(void) sscanf(buf, "%s", sysnam);
if (!strcmp(sysnam, prev_name)) {
if (called == SUCCESS)
continue;
}
/*
* If a system name was specified, skip til we find it
* If none was specified, only call if there is work.
*/
if (sys) {
if (strcmp(sys, sysnam) != 0)
continue;
} else {
DEBUG(3,"searching for outbound to %s\n", sysnam);
if (!work_scan(sysnam)) {
DEBUG(3,"no work for %s\n", sysnam);
called = SUCCESS; /* Don't try further */
continue;
}
DEBUG(2, "uucico: found work for %s\n", sysnam);
}
called = call_sysline(buf);
if (called == SUCCESS && sys)
break;
}
fclose(lsys);
if (called == FAIL && sys)
DEBUG(0, "Could not call system %s\n", sys);
return 0;
}
/*
* Call out to a system, given its L.sys line.
*/
call_sysline(lsysline)
char *lsysline;
{
static char tempname[MAX_HOST + 30 + SLOP];
static char strbuf[MAX_STRING+SLOP];
char *sysnam,
*times,
*acu,
*sbaud,
*telno,
*send,
*expct;
int baud;
who[0] = '-'; who[1] = '\0'; /* No user now (for logit) */
/* FIXME, use the values it is ignoring here */
sysnam = strtok(lsysline, " ");
times = strtok(NULL, " "); /* Time */
acu = strtok(NULL, " "); /* ACU */
sbaud = strtok(NULL, " "); /* Baud */
telno = strtok(NULL," "); /* phone */
strcpy(host_name, sysnam);
if ((!ignore_time_restrictions) && (strcmp(times,"Any"))) {
/* FIXME, check the time parameter and return FAIL if
* it does not allow calls now. Meanwhile, bounce
* all calls unless -S is specified. */
ulog(-1, "Wrong Time To Call %s", sysnam);
return FAIL;
}
baud = atoi(sbaud);
/* FIX ME, acu not implemented ? */
DEBUG(4, "Opening outgoing line %s\n", acu);
if (openout(acu, baud) != SUCCESS)
return FAIL;
if (Overide == 0) {
if (dial_nbr(telno)) {
ulog(-1, "FAILED call to %s", host_name);
return FAIL;
}
}
/* FIXME, log tty, baud rate, ... */
ulog(-1, "DIALED %s", host_name);
/*
* Process send-expect strings.
* FIXME, deal with "-", BREAK, etc.
*/
while (send = (char*)strtok((char *)NULL, " ")) {
if (send[0] != '"' || send[1] != '"' || send[2] != '\0') {
if (instr(send, strlen(send)))
goto bort1;
}
if (expct = (char*)strtok((char *)NULL, " ")) {
/* FIXME secondary strings, e.g. ogin:-EOT-ogin: */
xlat_str(expct, strbuf);
/*twrite(strbuf, strlen(strbuf));*/
}
}
/*
* FIXME, there should be a way to detect login/passwd
* failure here and keep doing the script rather than
* continuing to expect Shere at another login: prompt.
*/
ulog(-1, "SUCCEEDED call to %s", host_name);
if (getname(1)) /* get name */
goto bort1;
/* send response */
sprintf(tempname, "\20S%s -Q0 -x%d\0", our_name, debug);
twrite(tempname, strlen(tempname)+1); /* Including null */
/* wait for ok message, wait for protocol request
* send protocol 'g' response */
/* FIXME, we don't actually wait for the ROK message, since
* it is immediately followed by the Pprotos message. We
* currently just look for a Pg message. This needs work.
* FIXME, WE CAN'T TALK TO SITES THAT SUPPORT more than 'g'.
*/
if (instr(msgo3a, sizeof(msgo3a)-1)) {
if (!get_proto())
goto bort1;
}
twrite( msgi3, sizeof(msgi3)-1);
if (turnon(1))
goto bort1;
ulog(-1, "OK Startup");
top_level(1);
hangup();
return SUCCESS;
bort1:
hangup();
return FAIL;
}
/* Handle a single uucp [slave] login session */
do_session(ontheline)
int ontheline;
{
if (ontheline == 0) {
/* output login request, verify uucp */
twrite(msgo0,sizeof(msgo0)-1);
if (instr(msgi0,sizeof(msgi0)-1)) {
printf("uucico: invalid login name\n");
goto bort;
}
/* output password request, verify s8000 */
twrite(msgo1,sizeof(msgo1)-1);
if (instr(msgi1,sizeof(msgi1)-1)) {
printf("uucico: invalid password\n");
goto bort;
}
printf("uucico: correct login\n");
}
/*
* send Shere=<myhost>
*
* Apparently mac UUCP has a bug that only allows 7
* char host names, and it fails if it gets shere=<myhost>
* where <myhost> is > 7 chars.
*/
/*strcpy(msgo2 + MSGO2IDX, our_name);*/
twrite(msgo2,strlen(msgo2)+1);
/*
* get \020S<host> -Qn n (??)
*/
if (getname(0))
goto bort;
/* output ok message, output protocol request, wait for response */
twrite(msgo3,sizeof(msgo3)-1);
/* FIXME, make the protocol list here, and use it */
twrite(msgo3b,sizeof(msgo3b)-1);
if (instr(msgi3,sizeof(msgi3)-1))
goto bort;
if (turnon(0))
goto bort;
ulog(-1, "OK Startup");
top_level(0);
bort:
if (debug > 0)
printf("uucico: call complete\n");
return (1);
}
/*
* Handle transactions "at top level", as Unix uucp's debug log says.
*
* As master, we scan our queues for work and send requests to the
* other side. When done, we send a hangup request and switch to slave mode.
*
* As slave, we accept requests from the other side; when it is done,
* it sends a hangup request, and we switch to master mode, if we have
* any work queued up for that system.
*
* This repeats as long as either side has work to do. When all the
* queued work is done, we agree to hang up, terminate the packet protocol,
* and return to the caller. (We still haven't hung up the phone line yet.)
*
* A curious feature of the hangup protocol is that it is not a simple
* question-answer. The master says "H", asking about hangup. The
* slave responds "HY" saying OK. The master then says "HY" also,
* then both of them hang up. Maybe this is to make sure the first HY
* got ack'ed? Anyway, an "H" is reported as HANGUP and an "HY" as
* HANGNOW. After we send an HY, we go back to listening for commands;
* if the master sends something other than HY, we'll do it.
*/
#define HANGUP 2 /* Signal to switch master/slave roles */
#define HANGNOW 3 /* Signal to hang up now */
#define COPYFAIL 4 /* File copy failed */
int
top_level(master_mode)
int master_mode;
{
static char buf[MAXMSGLEN]; /* For hangup responses */
if (master_mode) {
(void) work_scan(host_name); /* Kick off queue scan */
goto master;
}
for (;;) {
slave: /* SLAVE SIDE */
for (;;) {
DEBUG(4, "*** TOP *** - slave\n", 0);
switch (do_one_slave()) {
case SUCCESS:
break;
case FAIL:
return FAIL;
case HANGUP:
if (work_scan(host_name)) {
if (wrmsg("HN"))
return FAIL;
goto master;
} else {
if (wrmsg("HY"))
return FAIL;
break; /* go to master mode */
}
case HANGNOW:
goto quit;
}
}
master: /* MASTER SIDE */
for (;;) {
DEBUG(4, "*** TOP *** - master\n", 0);
switch (do_one_master()) {
case SUCCESS:
break;
case FAIL:
return FAIL;
case HANGUP:
/* We wrote an H command, what's the resp? */
if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
return FAIL;
}
if (buf[0] != 'H')
return FAIL;
if (buf[1] == 'N')
goto slave;
else {
/* Write the final HY */
if (wrmsg("HY"))
return FAIL;
goto quit;
}
}
}
}
quit:
/* Shut down the packet protocol */
turnoff();
/* Write the closing sequence */
twrite(msgo4, sizeof(msgo4)-1);
(void) instr(msgi4, sizeof(msgi4)-1);
twrite(msgo4, sizeof(msgo4)-1);
strcpy(who, "-");
ulog(-1, "OK Conversation complete");
return SUCCESS; /* Go byebye */
}
/*
* We are slave; get a command from the other side and execute it.
*
* Result is SUCCESS, FAIL, HANGUP, or HANGNOW.
*/
int
do_one_slave()
{
static char msg[MAXMSGLEN]; /* Master's message to us */
/* Get master's command */
if (rdmsg(msg, MAXMSGLEN) != SUCCESS)
return FAIL;
/* Print it for easy debugging */
DEBUG(5,"\nCommand: %s\n\n", msg);
switch (msg[0]) {
case 'S':
if (msg[1] != ' ')
break;
return host_send_file(msg);
case 'R':
if (msg[1] != ' ')
break;
return host_receive_file(msg);
case 'X':
/*
* Cause uuxqt to run (on certain files?)
* See Protocol.doc for sketchy details.
*/
break;
case 'H':
if (msg[1] == '\0') return HANGUP;
if (msg[1] == 'Y') return HANGNOW;
if (msg[1] == 'N') return SUCCESS; /* Ignore HN to slave */
break;
}
/* Unrecognized packet from the other end */
DEBUG(0, "Bad control packet refused: %s\n", msg);
if (yesno(msg[0], 0, 0)) /* FIXME: return error code */
return FAIL;
return SUCCESS;
}
/*
* Do one piece of work as master.
*
* FIXME: we don't handle the flags, e.g. -c, properly!
*
* Now only dequeues queue file if all transfers were successful.
*/
int
do_one_master()
{
FILE *fd;
char *sname;
char cmnd[1]; /* Command character */
static char buf[256];
int fail = SUCCESS;
int failaccum = 0;
int num;
int delmeflag;
static char notify[NAMESIZE]; /* A bit large...FIXME */
char *delList[16]; /* delete files list */
short di = 0;
/* FIXME: do the notify stuff */
sname = work_next();
if (!sname) {
/* No more work, time to hang up. */
if (wrmsg("H"))
return FAIL;
return HANGUP;
}
DEBUG(2, "Request file %s\n", sname);
LockFile(sname);
fd = fopen(sname, "r");
if (fd == NULL) {
UnLockFile(sname);
DEBUG(0, "uucico: couldn't open %s\n", sname);
return SUCCESS;
}
while (fgets(buf, sizeof buf, fd)) {
DEBUG(3, "Queued request: %s", buf);
if (buf[1] != ' ')
goto badnum;
num = sscanf(buf, "%s %s %s %s %s %s %o\n",
cmnd, srcnam, dstnam, who, flags, temp, &mode, notify
);
switch (cmnd[0]) {
case 'S':
if (num < 7 || num > 8)
goto badnum;
fail = local_send_file(buf, &delmeflag);
if (delmeflag) {
if (di == sizeof(delList)/sizeof(delList[0])) {
ulog(-1, "Too many source files in Cmd file! %s", sname);
} else {
delList[di] = malloc(strlen(temp) + 1);
strcpy(delList[di], temp);
++di;
}
}
break;
case 'R':
if (num != 5)
goto badnum;
fail = local_receive_file(buf);
break;
default:
badnum:
DEBUG(0, "Unknown/invalid queued request: %s\n", buf);
++fail;
break;
}
if (fail != SUCCESS)
++failaccum;
/* FIXME, what does uucp do if one of N xfers fails? */
if (fail == FAIL) {
ulog(-1, "Error in work file %s", sname);
ulog(-1, "Bad line is: %s", buf);
}
}
fclose(fd);
/*
* If we successfuly copied everything zap the queue file
* and any local data files...
*/
if (failaccum == 0) {
while (di) {
--di;
remove(delList[di]);
free(delList[di]);
}
fail = remove(sname);
UnLockFile(sname);
if (fail != 0) {
ulog(-1, "Unable to remove work file %s", sname);
DEBUG(0, "Can't remove, errno %d\n", errno);
} else {
DEBUG(4, "Removed work file %s\n", sname);
}
} else {
UnLockFile(sname);
}
return SUCCESS;
}
/* Send a "yes or no" packet with character 'c'. */
int
yesno(c, true, err)
char c;
int true;
int err;
{
char buf[21];
buf[0] = c;
buf[1] = true? 'Y': 'N';
buf[2] = 0;
if (err && !true)
sprintf(buf+2,"%d", err);
return wrmsg(buf);
}
/*
* SLAVE MODE, Master wishes to send a file to us
*
* SECURITY: If file is not in list of allowed directories
* disallow transfer. UUSPOOL: is always in the
* list.
*
* If file is for UUSPOOL: (the current dir), disallow "C." files
* NOTE: success return and file redirected to T: as this can
* occur only if somebody purposefully is trying to break us.
*
* Return 0 = success
*/
int
host_send_file(msg)
char *msg;
{
FILE *fddsk; /* Disk file pointer */
char cmnd[1]; /* Command character */
int r;
int nor = 0;
sscanf(msg,"%s %s %s %s %s %s %o",
cmnd, srcnam, dstnam, who, flags, temp, &mode);
ulog(-1, "REQUESTED %s", msg);
munge_filename(dstnam, dstnam); /* Translate to local name */
strcpy (temp, TmpFileName(dstnam)); /* Create a handy temp file */
if (SecurityDisallow(dstnam, 'w')) {
ulog(-1, "REQUEST FAILED -- SECURITY");
if (yesno('S', 0, 4))
return FAIL;
return SUCCESS;
}
if (SecurityDisallow(dstnam, 'c') > 0) {
ulog(-1, "REQUEST FAILED -- SECURITY, REMOTE TRIED TO SEND");
ulog(-1, "US A COMMAND FILE: %s, FILE COPIED TO T:Bad-Cmd", dstnam);
strcpy(dstnam, "T:Bad-Cmd");
nor = 1;
}
/* FIXME: deal with file modes now that we fopen. */
LockFile(temp);
fddsk = fopen(temp, "wb" /*, mode|0600 */);
if (fddsk == NULL) {
UnLockFile(temp);
/* Can't open file -- send error response */
if (debug > 0) {
printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
temp,
dstnam,
errno
);
}
ulog(-1, "REQUEST FAILED -- TEMP FILE");
if (yesno('S', 0, 4))
return FAIL;
return SUCCESS;
}
/* FIXME: Are the above permissions right?? */
/* FIXME: Should we create directories for the file? */
if (yesno('S',1, 0)) { /* Say yes */
fclose(fddsk);
unlink(temp);
UnLockFile(temp);
return 1;
}
r = receive_file(fddsk, temp, dstnam, srcnam, nor);
UnLockFile(temp);
return(r);
}
/*
* SLAVE MODE, Master wants us to send a file to it
*
* SECURITY: If file is not in list of allowed directories
* disallow transfer. UUSPOOL: is always in the
* list.
*
* 0 = sucess
*/
host_receive_file(msg)
char *msg;
{
FILE *fddsk; /* Disk file descriptor */
int x;
char cmnd[1]; /* Command character */
ulog(-1, "REQUESTED %s", msg);
sscanf(msg,"%s %s %s",cmnd,srcnam,dstnam);
munge_filename(srcnam, temp);
if (SecurityDisallow(srcnam, 'r')) {
ulog(-1, "COPY FAILED -- SECURITY");
if (yesno('S', 0, 4))
return FAIL;
return SUCCESS;
}
fddsk = fopen(temp, "rb"); /* Try to open the file */
if (fddsk == NULL) {
/* File didn't open, sigh. */
if (debug > 0) {
printf("Cannot open file %s (%s) for reading, errno=%d\n",
temp, srcnam, errno
);
}
ulog(-1, "DENIED CAN'T OPEN %s", temp);
if (yesno('R', 0, 2))
return 1;
return 0;
}
if (yesno('R',1, 0)) { /* Say yes */
fclose(fddsk);
return 1;
}
x = send_file(fddsk);
switch (x) {
default:
return x;
case COPYFAIL:
/* We don't care if the copy failed, since the master
asked for the file and knows the result. */
return SUCCESS;
}
return 1;
}
/*
* MASTER MODE, We want to send a file.
*
* Return FAIL, SUCCESS, or COPYFAIL.
*
* SUCCESS is returned either if the file was not found locally (local
* error, and the queued transfer should be flushed) or if it was moved
* successfully. COPYFAIL indicates that the queued transfer should be
* left queued, and later retried. FIXME, there are several failure points
* in the transaction (see Protocol.doc) and we need finer control here.
*/
int
local_send_file(workstr, delmeflag)
char *workstr;
int *delmeflag;
{
static char buf[MAXMSGLEN]; /* Used for both xmit and receive */
FILE *fddsk; /* Disk file descriptor */
int res; /* Result and file removal status */
*delmeflag = 0;
/* WHY are temp and srcnam switched? FIXME! And no notify? */
sprintf(buf,"S %s %s %s %s %s 0%o %s",
temp, dstnam, who, flags, srcnam, mode, who
);
ulog(-1, "REQUEST %s", buf);
if (strchr(flags, 'c')) {
munge_filename(srcnam, temp);
} else {
munge_filename(temp, temp);
}
LockFile(temp);
fddsk = fopen(temp, "rb");
if (fddsk == NULL) {
UnLockFile(temp);
/* FIXME -- handle queued request for nonexistent file */
if (debug > 0)
printf("Can't open file %s (%s), errno=%d\n",
temp,
srcnam,
errno
);
ulog(-1, "NOT FOUND %s", temp);
/* return COPYFAIL;*/
return SUCCESS; /* assume file previously sent */
}
/* Tell the other side we want to send this file */
if (wrmsg(buf) != SUCCESS) {
DEBUG(0, "problem sending request\n", 0);
fclose(fddsk);
UnLockFile(temp);
return FAIL;
}
/* See what they have to say about it */
if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
fclose(fddsk);
UnLockFile(temp);
return FAIL;
}
if ((buf[0] != 'S') || (buf[1] != 'Y')) {
ulog(-1, "REQUEST DENIED %s", buf);
fclose(fddsk);
UnLockFile(temp);
return FAIL;
}
res = send_file(fddsk); /* FAIL, SUCCESS, or COPYFAIL */
/* Delete the source file if it was just a copy */
if (res != SUCCESS) {
UnLockFile(temp);
return res;
}
if (strchr(flags, 'c')) { /* If copied direct from source */
UnLockFile(temp);
return res; /* ...just return. */
}
*delmeflag = 1;
UnLockFile(temp);
return res;
}
/*
* MASTER MODE, We wish to receive a specific file so we ask for it
*
* Return 0 = success
*/
int
local_receive_file()
{
static char buf[MAXMSGLEN];
FILE *fddsk; /* Disk file pointer */
int r;
/* FIXME, test dest file access before we ask for it. */
sprintf(buf,"R %s %s %s %s %s 0%o %s",
srcnam, dstnam, who, flags, temp, mode, who
);
munge_filename(dstnam, dstnam); /* tlate to local name */
strcpy (temp, TmpFileName(dstnam)); /* Create a handy temp file */
/* FIXME: deal with file modes now that we fopen. */
/* FIXME: Are the above permissions right?? */
/* FIXME: Should we create directories for the file? */
LockFile(temp);
fddsk = fopen(temp, "wb" /*, mode|060 */);
if (fddsk == NULL) {
UnLockFile(temp);
/* Can't open temp file -- send error response */
if (debug > 0) {
printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
temp,
dstnam,
errno
);
}
ulog(-1, "REQUEST FAILED -- TEMPFILE");
return FAIL;
}
ulog(-1, "REQUEST %s", buf);
if (wrmsg(buf) != SUCCESS) {
fclose(fddsk);
UnLockFile(temp);
printf("uucico: problem sending request\n");
return FAIL;
}
/* See what the other side has to say about it */
if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
fclose(fddsk);
UnLockFile(temp);
return FAIL;
}
if ((buf[0] != 'R') || (buf[1] != 'Y')) {
ulog(-1, "REQUEST DENIED %s", buf);
fclose(fddsk);
UnLockFile(temp);
return SUCCESS; /* FIXME, should do something more here */
}
r = receive_file(fddsk, temp, dstnam, srcnam, 0);
UnLockFile(temp);
return(r);
}
/*
* General receive file
*/
int
receive_file(fddsk, temp, dstnam, srcnam, norename)
FILE *fddsk;
char *temp, *dstnam, *srcnam;
{
int status;
int error = 0; /* No errors so far */
if (rddata(fddsk) != SUCCESS)
error++;
status = fclose(fddsk); /* Make sure the data got here */
if (status != 0) {
error++;
DEBUG(0, "fclose errno=%d\n", errno);
}
/*
* Move the file from its temp location to its real location,
* This needs to be able to copy a file if a simple rename
* does not suffice. Should create directories if necesary.
* should use source ]name if target is a directory (i.e. no
* target source name
*/
unlink(dstnam);
if (norename) /* for security redirect */
status = 0;
else
status = rename(temp, dstnam);
if (status != 0) {
error++;
if (debug > 0) {
printf("Cannot rename file %s to %s, errno=%d\n",
temp, dstnam, errno);
}
}
ulog(-1, "COPY %s", error ? "FAILED": "SUCCEEDED");
if (yesno('C', error == 0, 5)) /* Send yes or no */
return FAIL;
return SUCCESS;
}
/*
* general file send routine
* Return SUCCESS, FAIL, or COPYFAIL.
*/
int
send_file(fddsk)
FILE *fddsk; /* Disk file pointer */
{
static char ansbuf[MAXMSGLEN];
if (wrdata(fddsk) != SUCCESS) {
fclose(fddsk);
return COPYFAIL;
}
fclose(fddsk);
/* Await the "CY" or "CNddd" packet, and toss it. */
while (1) {
if (rdmsg(ansbuf, MAXMSGLEN) != SUCCESS)
return COPYFAIL;
if (ansbuf[0] != 'C') {
DEBUG(0,"\nDidn't get 'CY' or 'CN', got %s\n", ansbuf);
/* and loop looking for C message */
} else if (ansbuf[1] == 'Y') {
ulog(-1, "REQUESTED %s", ansbuf);
return SUCCESS;
} else {
ulog(-1, "COPY FAILED %s", ansbuf);
return COPYFAIL;
}
}
return COPYFAIL;
}